Centralize visible issue filtering and Done retention#222
Conversation
- Extract MobileNav into src/components/mobile-nav.tsx with React state - Add theme toggle and version label inside mobile nav panel - Nav closes automatically when a link is tapped (hashchange + onClick) - Desktop nav hidden on small screens (hidden sm:flex) - Header and main content use consistent max-w-screen-2xl container
- Restore version label to desktop header (was accidentally removed) - Conditionally render mobile nav content only when open to avoid duplicate DOM elements (version label, theme toggle) - Update tests: use fireEvent for checkbox interaction, add new test for sm:hidden container, verify nav links on open
- Add src/lib/version-client.ts with getClientVersionLabel() that uses only NEXT_PUBLIC_DISPATCH_VERSION (no Node.js fs imports) - mobile-nav.tsx now uses getClientVersionLabel to avoid bundling node:fs into the client bundle (Turbopack chunking error)
- ThemeToggle now renders inside mobile nav footer alongside version label - Desktop header still has its own ThemeToggle (right-aligned via ml-auto) - Update test to query desktop toggle via .ml-auto selector instead of getByLabelText which would match both instances
- Add BOARD_COLUMNS as shared source of truth in src/types/index.ts - Derive STATUS_LABELS from BOARD_COLUMNS to prevent drift - Update KanbanBoard to use BOARD_COLUMNS instead of local COLUMNS - Update Projects page to use BOARD_COLUMNS with human-readable titles - Add tests for BOARD_COLUMNS canonical order and STATUS_LABELS derivation - Update ProjectsPage test to expect human-readable column titles
- Add buildVisibleIssueWhere() shared helper in src/lib/issue-filters.ts - Add getDoneRetentionDays() with DISPATCH_DONE_RETENTION_DAYS support (default 7) - Update Board page to use the shared helper instead of inline logic - Update Projects page to use the shared helper instead of inline logic - Update Issues API route to use shared helper (was open-only, now applies done retention) - Add comprehensive tests for buildVisibleIssueWhere and getDoneRetentionDays - Add tests for GET /api/issues route covering filtering behavior Fixes #196
|
✅ Automated recommendation: APPROVE Analysis engine: MiniMax-M2.7@https://litellm.jory.dev/v1 (anthropic) SummaryThis PR centralizes visible issue filtering across Board, Projects, and the Issues API route using a shared helper function ( Change-by-Change Findings
|
| Criterion | Status |
|---|---|
| Board and Projects share Done retention behavior via shared helper | ✅ Both pages now use buildVisibleIssueWhere() from src/lib/issue-filters.ts |
| Issues API route applies the same done retention | ✅ Fixed from open-only to open + 7-day Done retention |
| Default retention is 7 days | ✅ DEFAULT_DONE_RETENTION_DAYS = 7, confirmed in tests |
includeClosed=true still works |
✅ Both helper and route tests verify this |
DISPATCH_DONE_RETENTION_DAYS env var support |
✅ Implemented in getDoneRetentionDays(), tested |
Implementation matches suggested approach from issue: shared helper function buildVisibleIssueWhere({ includeClosed, doneRetentionDays, filters }) with env var support.
Tool Harness Findings
No tool requests were executed. The PR is a refactoring change (no image updates, no version changes) that can be fully validated through code review of the diff and test coverage provided.
Unknowns / Needs Verification
-
Test count (938): PR claims "All 938 tests pass" — this was not independently verified as tool harness ran in plan-only mode with no requests executed. The test suite size (+261 test lines across two files) is substantial and covers the new functionality.
-
CI validation: Standard GitHub Actions workflow should run lint, typecheck, tests, and build automatically. The PR body states these are clean but this reviewer cannot confirm without execution.
Summary
This PR centralizes visible issue filtering across Board, Projects, and the Issues API route using a shared helper function. This ensures consistent Done retention behavior across all views.
Changes
New shared helpers in
src/lib/issue-filters.tsbuildVisibleIssueWhere(where, options)— Adds OR-based visibility filtering to a Prisma where clause:includeClosed=true: all issues, no state filtergetDoneRetentionDays()— ReadsDISPATCH_DONE_RETENTION_DAYSenv var, defaults to7Updated pages/routes to use shared helper
src/app/board/page.tsx) — Replaced inline filtering logic withbuildVisibleIssueWhere()src/app/projects/page.tsx) — Replaced inline filtering logic withbuildVisibleIssueWhere()src/app/api/issues/route.ts) — Key fix: was filtering to open-only by default, now applies done retention window (7 days) matching Board and ProjectsTests
buildVisibleIssueWhere()covering:includeClosed=trueshows all issuesdoneRetentionDaysoptiongetDoneRetentionDays()covering:DISPATCH_DONE_RETENTION_DAYSenv var supportsrc/app/api/issues/route.test.tscovering:includeClosed=truequery paramAcceptance criteria met
DISPATCH_DONE_RETENTION_DAYS)Fixes #196